package com.imooc.sm.global;


import com.imooc.sm.entity.Log;
import com.imooc.sm.entity.Staff;
import com.imooc.sm.service.LogService;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;

/*
这些代码超级重要，超级牛掰~~~
@Component(一般的类),与 Repository Service Controller 功能一样
@Aspect 植入对象
业务层填充两个属性，控制层填充四个属性
 */
@Component
@Aspect
public class LogAdvice {

    @Autowired
    private LogService logService;

    /**
     *操作日志
     * @After ：在执行完Controller后执行切面，进行增强
     * controller下面任意限制的任意方法，任意返回值，任意参数都增强，
     *   注意SelfController里面的除外，
     *     注意to什么的方法也屏蔽
     */
    @After("execution(* com.imooc.sm.controller.*.*(..))" +
            "&& !execution(* com.imooc.sm.controller.SelfController.*(..))" +
            "&& !execution(* com.imooc.sm.controller.*.to*(..))")
    public void operationLog(JoinPoint joinPoint){
        Log log = new Log();
        /**
         *想看是哪个模块的日志，可以通过类名字获得，操作可以用方法名获得 ,所以需要joinPoint
         * 获得切入对象，得到这个类getClass()/签名对象getSignature()，得到具体的信息
         */
        log.setMoudle(joinPoint.getTarget().getClass().getSimpleName());
        log.setOperation(joinPoint.getSignature().getName());

        //得到切入点的参数数组,得到request,得到user, 得到 account
        HttpServletRequest request = (HttpServletRequest)joinPoint.getArgs()[0];
        HttpSession session = request.getSession();
        Object object = session.getAttribute("USER");
        Staff staff = (Staff) object;
        log.setOperator(staff.getAccount());
        //Controller执行后，运行切面，所以设置状态成功,并且添加日志。
        log.setResult("成功");
        logService.addOperationLog(log);
    }


    /**
     *系统日志:当程序出现异常后的切面处理
     * @AfterThrowing ：出现异常后执行切面，进行增强
     * 此处需要引入异常对象 throwable
     *   注意SelfController里面的除外
     */
    @AfterThrowing(throwing = "throwable",pointcut = "execution(* com.imooc.sm.controller.*.*(..))" +
            "&& !execution(* com.imooc.sm.controller.SelfController.*(..))")
    public void systemLog(JoinPoint joinPoint,Throwable throwable){
        Log log = new Log();

        log.setMoudle(joinPoint.getTarget().getClass().getSimpleName());
        log.setOperation(joinPoint.getSignature().getName());

        //得到切入点的参数数组,得到request,得到user, 得到 account
        HttpServletRequest request = (HttpServletRequest)joinPoint.getArgs()[0];
        HttpSession session = request.getSession();
        Object object = session.getAttribute("USER");
        Staff staff = (Staff) object;
        log.setOperator(staff.getAccount());
        /**
         *此处应该是异常的名字
         */
        log.setResult(throwable.getClass().getName());
        logService.addSystemLog(log);
    }


    /**
     *登录日志
     *只是在 SelfController 的 login 方法后处理
     */
    @After("execution(* com.imooc.sm.controller.SelfController.login(..))")
    public void loginLog(JoinPoint joinPoint){
        log(joinPoint);
    }


    /**
     *退出日志
     *退出方法之前处理
     */
    @Before("execution(* com.imooc.sm.controller.SelfController.logout(..))")
    public void logoutLog(JoinPoint joinPoint){
        log(joinPoint);
    }


    //被调用的方法
    public void log(JoinPoint joinPoint){
        Log log = new Log();
        log.setMoudle(joinPoint.getTarget().getClass().getSimpleName());
        log.setOperation(joinPoint.getSignature().getName());
        HttpServletRequest request = (HttpServletRequest)joinPoint.getArgs()[0];
        HttpSession session = request.getSession();
        Object object = session.getAttribute("USER");
        //此处需要判断登录是否成功
        if (object == null){
            //此时可以从request中得到用户输入的账号
            log.setOperator(request.getParameter("account"));
            log.setResult("失败");
        }else{
            Staff staff = (Staff) object;
            log.setOperator(staff.getAccount());
            log.setResult("成功");
        }
        logService.addOperationLog(log);
    }
}
